<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script>
    /*
    * 单例模式：
    *   单例模式是一种非常常用但又非常简单的设计模式。它是指在一个类中，只能有一个实例对象，即使多次实例化该类，
    *   也只能返回第一次实例化该类后的实例对象。
    *
    * 单例模式思路：
    *   一个类能返回一个对象的引用（并且永远是同一个）和一个获得该实例的方法。
    *
    * 没有使用单例模式：
    *   实例化一个类A 开辟一个内存空间 p1
    *   再次实例化这个类A 又开辟一个内存空间 p2
    *   实例化多少次，就开辟多少个
    *
    * 使用单例模式：
    *   实例化一个类A 开辟一个内存空间 p1
    *   再次实例化这个类A 开辟一个内存空间，不过是第一次实例化该类开辟的内存空间p1
    *   同一个类无论实例化多少次，都只返回第一次实例化的对象
    *
    * 单例模式的使用场景：
    *   比如点击一个按钮，没有使用单例模式，点击一次该按钮，弹出一个提示框，点击99次该按钮，弹出99个提示框
    *   使用单例模式之后，点击该按钮，无论点击多少次，都只弹出一次提示框
    *
    * */
    //ES5没有使用单例模式
    function Demo1(){
        this.name = "remi"
        this.age = 18
        this.sex = "boy"
    }

    var remi1 = new Demo1() //此时实例化该构造函数
    console.log(remi1.name)

    var tongtong1 = new Demo1() //此时又实例化该构造函数
    console.log(tongtong1.name)

    console.log(remi1 === tongtong1) //这时肯定是false，是两个完全不同的对象

    //ES5中改成使用单例模式
    //静态属性和静态方法不需要new，直接打点调用即可
    function Demo(name){

        //第一次实例化的话 Demo.unique === undefined，不是第一次实例化，Demo.unique是有值的等于实例化后的对象this，就不是undefined
        if(Demo.unique !== undefined){ //如果不全等与undefined，说明不是第一次实例化，既然不是第一次实例化，那就进行该操作
            return Demo.unique //那就返回第一次实例化后的对象
        }

        //如果是第一次实例化，Demo.unique就是undefined，就不走上面的if，就进行下面操作
        this.name = name
        this.age = 18
        this.sex = "boy"

        //添加一个独一无二的静态的属性，将unique属性赋值为第一次实例化之后的对象this，以后每次实例化都是用该对象
        Demo.unique = this //this代表实例化后的对象
    }

    var remi = new Demo("remi") //此时实例化该构造函数
    console.log(remi.name)

    var tongtong = new Demo("tongtong") //此时又实例化该构造函数
    console.log(tongtong.name)

    console.log(remi === tongtong) //这时肯定是true，这两个都是同一个实例对象


    //ES6使用单例模式
    class Demo2{
        constructor(){
            this.name = "remi"
        }

        //静态方法，获取单例模式
        static getInstance(){
            if(!this.instance){ //this.instance是自己创造的一个属性，一开始肯定是undefined，取反则为true，进入该if判断并执行其中代码
                this.instance = new Demo2() //将this.instance赋值为实例化该类的对象
            }
            return this.instance //返回this.instance，第一次为undefined，进入if判断，实例化该类Demo2，得到第一次实例化的对象
            //之后每次实例化该类Demo2，this.instance都已经有值了，是第一次实例化后的对象，则不进入if判断，直接返回第一次实例化后的对象
        }
    }
    let Remi = Demo2.getInstance() //第一次实例化并调用单例模式静态方法
    let TongTong = Demo2.getInstance() //第二次实例化并调用单例模式静态方法
    console.log(Remi = TongTong) //true

    let Remi1 = new Demo2() //如果不调用单例模式方法，则生成的不是单例模式对象
    let TongTong1 = new Demo2()
    console.log(Remi1 === TongTong1)

</script>
</body>
</html>